#include "BaseTabWidget.h"

#include <QApplication>
#include <QMouseEvent>

BaseTabWidget::BaseTabWidget(QWidget *parent) : CTabWidget(parent) {
    setAttribute(Qt::WA_StyledBackground);

    m_previousTab = nullptr;
    m_currentTab = nullptr;

    tabBar()->installEventFilter(this);
    connect(this, &CTabWidget::currentChanged, this, &BaseTabWidget::handleTabIndexChanged);
}

BaseTabWidget::~BaseTabWidget() {
}

int BaseTabWidget::addTab(BaseTab *tab, const QString &label) {
    connect(tab, &BaseTab::tabNameChanged, this, &BaseTabWidget::handleTabNameChanged);
    int res = CTabWidget::addTab(tab, label);
    addTabCore(res);

    return res;
}

int BaseTabWidget::addTab(BaseTab *tab, const QIcon &icon, const QString &label) {
    connect(tab, &BaseTab::tabNameChanged, this, &BaseTabWidget::handleTabNameChanged);
    int res = CTabWidget::addTab(tab, icon, label);
    addTabCore(res);

    return res;
}

int BaseTabWidget::insertTab(int index, BaseTab *tab, const QString &label) {
    connect(tab, &BaseTab::tabNameChanged, this, &BaseTabWidget::handleTabNameChanged);
    int res = CTabWidget::insertTab(index, tab, label);
    addTabCore(res);

    return res;
}

int BaseTabWidget::insertTab(int index, BaseTab *tab, const QIcon &icon, const QString &label) {
    connect(tab, &BaseTab::tabNameChanged, this, &BaseTabWidget::handleTabNameChanged);
    int res = CTabWidget::insertTab(index, tab, icon, label);
    addTabCore(res);

    return res;
}

BaseTab *BaseTabWidget::currentWidget() const {
    return qobject_cast<BaseTab *>(CTabWidget::currentWidget());
}

BaseTab *BaseTabWidget::tabAt(int index) const {
    if (index < 0 || index >= count()) {
        return nullptr;
    }
    return qobject_cast<BaseTab *>(CTabWidget::widget(index));
}

int BaseTabWidget::indexOf(BaseTab *tab) const {
    return CTabWidget::indexOf(tab);
}

void BaseTabWidget::setCornerWidget(BaseTab *w, Qt::Corner corner) {
    return CTabWidget::setCornerWidget(w, corner);
}

BaseTab *BaseTabWidget::cornerWidget(Qt::Corner corner) const {
    return qobject_cast<BaseTab *>(CTabWidget::cornerWidget(corner));
}

void BaseTabWidget::setCurrentWidget(BaseTab *tab) {
    return CTabWidget::setCurrentWidget(tab);
}

void BaseTabWidget::setTabTitle(int index, const QString &title) {
    setTabText(index, title);
    emit titleChanged(index, title);
}

QString BaseTabWidget::currentTitle() const {
    return tabText(currentIndex());
}

void BaseTabWidget::removeTab(int index) {
    BaseTab *tab = tabAt(index);
    disconnect(tab, &BaseTab::tabNameChanged, this, &BaseTabWidget::handleTabNameChanged);
    removeTabCore(index);
    CTabWidget::removeTab(index);
}

void BaseTabWidget::removeTab(BaseTab *tab) {
    int index = indexOf(tab);
    if (index < 0) {
        return;
    }
    removeTab(index);
}

BaseTab *BaseTabWidget::currentTab() const {
    return m_currentTab;
}

BaseTab *BaseTabWidget::previousTab() const {
    return m_previousTab;
}

int BaseTabWidget::previousIndex() const {
    return tabBar()->previousIndex();
}

void BaseTabWidget::invalidateHover() const {
    QHoverEvent *event = new QHoverEvent(QEvent::HoverLeave, QPointF(-1, -1), QPointF());
    QApplication::postEvent(tabBar(), event); // Send a fake hover event to tab bar
}

void BaseTabWidget::addTabCore(int index) {
    Q_UNUSED(index)
}

void BaseTabWidget::removeTabCore(int index) {
    Q_UNUSED(index)
}

void BaseTabWidget::tabIndexChangeCore(int index, bool changed) {
    Q_UNUSED(index)
    Q_UNUSED(changed)
}

void BaseTabWidget::setTabBar(CTabBar *bar) {
    CTabWidget::setTabBar(bar);
    bar->installEventFilter(this);
}

void BaseTabWidget::handleTabIndexChanged(int index) {
    BaseTab *currentTab = tabAt(index);
    if (m_currentTab == currentTab) {
        tabIndexChangeCore(index, false);
        return;
    }

    m_previousTab = m_currentTab;
    m_currentTab = currentTab;

    if (m_previousTab) {
        m_previousTab->leave();
    }
    if (m_currentTab) {
        m_currentTab->enter();
    }

    tabIndexChangeCore(index, true);
    emit realIndexChanged(index);
}

void BaseTabWidget::handleTabNameChanged(const QString &newName) {
    int index = -1;
    BaseTab *tab = qobject_cast<BaseTab *>(sender());
    // Modify parent window's title
    index = indexOf(tab);
    if (index >= 0) {
        setTabText(index, newName);
        emit titleChanged(index, newName);
    }
}

bool BaseTabWidget::eventFilter(QObject *obj, QEvent *event) {
    QTabBar *bar = tabBar();
    if (obj == bar) {
        if (event->type() == QEvent::MouseButtonPress) {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
            if (childAt(mouseEvent->pos()) == bar) {
                emit tabPressed(bar->tabAt(mouseEvent->pos()), mouseEvent->button());
            }
        } else if (event->type() == QEvent::MouseButtonRelease) {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
            if (childAt(mouseEvent->pos()) == bar) {
                emit tabReleased(bar->tabAt(mouseEvent->pos()), mouseEvent->button());
            }
        }
    }
    return CTabWidget::eventFilter(obj, event);
}
